import CryptoJS from 'crypto-js'

const SECRET_KEY = CryptoJS.enc.Utf8.parse('3333e6e143439161')
const SECRET_IV = CryptoJS.enc.Utf8.parse('e3bbe7e3ba84431a')

const config = {
  type: 'localStorage',
  prefix: 'SDF_0.0.1',
  expire: 0,
  isEncrypt: true
}

export const isSupportStorage = () => {
  return (typeof (Storage) !== 'undefined')
}

export const setStorage = (key, value, expire = 0) => {
  if (value === '' || value === null || value === undefined) {
    value = null
  }

  if (isNaN(expire) || expire < 0) throw new Error('Expire must be a number')

  expire = (expire || config.expire) * 1000
  let data = {
    value: value,
    time: Date.now(),
    expire: expire
  }

  const encryptString = config.isEncrypt
    ? encrypt(JSON.stringify(data))
    : JSON.stringify(data)

  window[config.type].setItem(autoAddPrefix(key), encryptString)
}

export const getStorage = (key) => {
  key = autoAddPrefix(key)
  if (!window[config.type].getItem(key) || JSON.stringify(window[config.type].getItem(key)) === 'null') {
    return null
  }

  const storage = config.isEncrypt
    ? JSON.parse(decrypt(window[config.type].getItem(key)))
    : JSON.parse(window[config.type].getItem(key))

  let nowTime = Date.now()

  if (storage.expire && config.expire * 6000 < (nowTime - storage.time)) {
    removeStorage(key)
    return null
  } else {
    setStorage(autoRemovePrefix(key), storage.value)
    return storage.value
  }
}

export const hasStorage = (key) => {
  key = autoAddPrefix(key)
  let arr = getStorageAll().filter((item) => {
    return item.key === key
  })
  return !!arr.length
}

export const getStorageKeys = () => {
  let items = getStorageAll()
  let keys = []
  for (let index = 0; index < items.length; index++) {
    keys.push(items[index].key)
  }
  return keys
}

export const getStorageForIndex = (index) => {
  return window[config.type].key(index)
}

export const getStorageLength = () => {
  return window[config.type].length
}

export const getStorageAll = () => {
  let len = window[config.type].length
  let arr = []
  for (let i = 0; i < len; i++) {
    let getKey = window[config.type].key(i)
    let getVal = window[config.type].getItem(getKey)
    arr[i] = {
      'key': getKey,
      'val': getVal
    }
  }
  return arr
}

export const removeStorage = (key) => {
  window[config.type].removeItem(autoAddPrefix(key))
}

export const clearStorage = () => {
  window[config.type].clear()
}

const autoAddPrefix = (key) => {
  const prefix = config.prefix ? config.prefix + '_' : ''
  return prefix + key
}

const autoRemovePrefix = (key) => {
  const len = config.prefix ? config.prefix.length + 1 : ''
  return key.substr(len)
}

const encrypt = (data) => {
  if (typeof data === 'object') {
    try {
      data = JSON.stringify(data)
    } catch (error) {
      console.log('encrypt error:', error)
    }
  }
  const dataHex = CryptoJS.enc.Utf8.parse(data)
  const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {
    iv: SECRET_IV,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  })
  return encrypted.ciphertext.toString()
}

const decrypt = (data) => {
  const encryptedHexStr = CryptoJS.enc.Hex.parse(data)
  const str = CryptoJS.enc.Base64.stringify(encryptedHexStr)
  const decrypt = CryptoJS.AES.decrypt(str, SECRET_KEY, {
    iv: SECRET_IV,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  })
  const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8)
  return decryptedStr.toString()
}
